package cmd

import (
	"errors"
	"fmt"
	"image"
	"image/draw"
	"image/gif"
	"image/jpeg"
	"image/png"
	"os"
	"path/filepath"
	"sync"

	"github.com/duke-git/lancet/v2/fileutil"
	"github.com/duke-git/lancet/v2/strutil"
	"github.com/nfnt/resize"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var (
	imagePath string //源图地址
	waterPath string //水印图地址
	distPath  string //保存位置

)

var envFile bool //是否env文件获取参数

var (
	left   uint //水印图坐标
	top    uint
	width  uint //水印图缩放大小
	height uint
)

var wg sync.WaitGroup

var rootCmd = &cobra.Command{
	Use:   "watermark",
	Short: "批量给图片加上水印图",
	Long: `watermark(1.0)可以给一批图片加上水印图,或者批量给图片加上不同的水印图,例如
	watermark  -p image.png  -w water.png  -t 400 -l 300
如参数在.env文件中定义,只需要执行
	watermark -e
	`,

	Run: func(cmd *cobra.Command, args []string) {

		if envFile {
			viper.SetConfigFile("./.env")
			err := viper.ReadInConfig()
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}

			imagePath = viper.GetString("SOURCE_PATH")
			waterPath = viper.GetString("WATER_PATH")
			distPath = viper.GetString("DIST_PATH")
			left = viper.GetUint("LEFT")
			top = viper.GetUint("TOP")
			width = viper.GetUint("WIDTH")
			height = viper.GetUint("HEIGHT")
		}

		sourceFiles, err := getAllfile(imagePath)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		waterFiles, err := getAllfile(waterPath)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		// fmt.Println(sourceFiles, waterFiles)
		// return
		err = createDir(distPath)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		work(sourceFiles, waterFiles)

	},
}

func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

func init() {

	rootCmd.Flags().BoolVarP(&envFile, "env", "e", false, "是否从env文件获取参数")
	rootCmd.Flags().StringVarP(&imagePath, "path", "p", "./background.png", "源图文件或目录")
	rootCmd.Flags().StringVarP(&waterPath, "water", "w", "./images", "水印图文件或目录")
	rootCmd.Flags().StringVarP(&distPath, "dist", "d", "./dist", "合成后保存的目录")
	rootCmd.Flags().UintVarP(&left, "left", "l", 0, "水印图左边到源图左边的距离,单位px")
	rootCmd.Flags().UintVarP(&top, "top", "t", 0, "水印图上边到源图上边的距离,单位px")
	rootCmd.Flags().UintVarP(&width, "width", "", 0, "水印图宽度,单位px")
	rootCmd.Flags().UintVarP(&height, "height", "", 0, "水印图高度,单位px")
}

func createDir(path string) error {
	f, err := os.Stat(path)
	if err == nil {
		if f.IsDir() {
			return nil
		}
		return errors.New("创建" + path + "失败")
	}
	return os.MkdirAll(path, 0666)
}

func getAllfile(path string) ([]string, error) {
	if fileutil.IsExist(path) {
		if fileutil.IsDir(path) {
			//是个目录
			files, err := fileutil.ListFileNames(path)
			if err != nil {
				return files, err
			}
			if len(files) == 0 {
				return files, errors.New(path + "是一个空目录")
			}

			var ret []string
			for _, file := range files {
				ret = append(ret, path+"/"+file)
			}
			return ret, nil
		}
		return []string{path}, nil
	}

	return []string{}, errors.New(path + "不存在")
}

func work(sourceFiles, waterFiles []string) {
	for _, sFile := range sourceFiles {
		sHandle, err := getImage(sFile)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		sFileName := getFileName(sFile)
		for _, wFile := range waterFiles {
			wg.Add(1)
			distFile := distPath + "/" + sFileName + "_" + getFileName(wFile) + ".png"
			go func(s image.Image, w, d string) {
				err := generate(s, w, d)
				if err != nil {
					fmt.Println(w, err)
				}
				wg.Done()
			}(sHandle, wFile, distFile)

		}
	}

	wg.Wait()
}

func getFileName(path string) string {

	return strutil.BeforeLast(filepath.Base(path), ".")

}

func generate(bimg image.Image, waterFile, savefile string) error {

	qrImg, err := getImage(waterFile)
	if err != nil {
		return err
	}
	if width == 0 {
		width = uint(qrImg.Bounds().Max.X)
	}
	if height == 0 {
		height = uint(qrImg.Bounds().Max.Y)
	}

	qrImg = resize.Resize(width, height, qrImg, resize.Lanczos3)

	bimgBounds := bimg.Bounds()
	m := image.NewRGBA(bimgBounds)
	draw.Draw(m, bimgBounds, bimg, image.Point{0, 0}, draw.Src)
	draw.Draw(m, qrImg.Bounds().Add(image.Pt(int(left), int(top))), qrImg, image.Point{0, 0}, draw.Src)
	imgDist, err := os.Create(savefile)
	if err != nil {
		return err
	}
	png.Encode(imgDist, m)
	imgDist.Close()
	return nil
}

func getImage(file string) (image.Image, error) {
	handle, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer handle.Close()
	img, _, err := image.Decode(handle)
	if err == nil {
		return img, nil
	}
	img, err = jpeg.Decode(handle)
	if err == nil {
		return img, nil
	}
	img, err = gif.Decode(handle)
	if err == nil {
		return img, nil
	}

	return nil, errors.New("未知类型")
}
